package cn.zl.GB28181.transmit.event.request;

import cn.zl.GB28181.transmit.SIPSender;
import cn.zl.GB28181.utils.ByteUtils;
import cn.zl.GB28181.utils.SipUtils;
import cn.yunbamboos.id.SnowflakeIdGenerator;
import gov.nist.javax.sip.message.SIPRequest;
import gov.nist.javax.sip.message.SIPResponse;
import jakarta.annotation.Resource;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.sip.InvalidArgumentException;
import javax.sip.PeerUnavailableException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.SipFactory;
import javax.sip.address.Address;
import javax.sip.address.AddressFactory;
import javax.sip.address.SipURI;
import javax.sip.header.ContentTypeHeader;
import javax.sip.header.ExpiresHeader;
import javax.sip.header.HeaderFactory;
import javax.sip.message.MessageFactory;
import javax.sip.message.Request;
import java.io.ByteArrayInputStream;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public abstract class BaseSIPRequestProcessor {

    private final static Logger logger = LoggerFactory.getLogger(BaseSIPRequestProcessor.class);

    @Resource
    protected SIPSender sipSender;
    @Resource
    protected SnowflakeIdGenerator snowflakeIdGenerator;

    public HeaderFactory getHeaderFactory() {
        try {
            return SipFactory.getInstance().createHeaderFactory();
        } catch (PeerUnavailableException e) {
            logger.error("未处理的异常 ", e);
        }
        return null;
    }

    public MessageFactory getMessageFactory() {
        try {
            return SipFactory.getInstance().createMessageFactory();
        } catch (PeerUnavailableException e) {
            logger.error("未处理的异常 ", e);
        }
        return null;
    }

    public static class ResponseAckExtraParam {
        String content;
        ContentTypeHeader contentTypeHeader;
        SipURI sipURI;
        int expires = -1;
    }

    /***
     * 回复状态码
     * 100 trying
     * 200 OK
     * 400
     * 404
     */
    @SuppressWarnings("UnusedReturnValue")
    public SIPResponse responseAck(SIPRequest sipRequest, int statusCode) throws SipException, InvalidArgumentException, ParseException {
        return responseAck(sipRequest, statusCode, null);
    }

    public SIPResponse responseAck(SIPRequest sipRequest, int statusCode, String msg) throws SipException, InvalidArgumentException, ParseException {
        return responseAck(sipRequest, statusCode, msg, null);
    }

    public SIPResponse responseAck(SIPRequest sipRequest, int statusCode, String msg, ResponseAckExtraParam responseAckExtraParam) throws SipException, InvalidArgumentException, ParseException {
        if (sipRequest.getToHeader().getTag() == null) {
            sipRequest.getToHeader().setTag(SipUtils.getNewTag());
        }
        SIPResponse response = (SIPResponse) getMessageFactory().createResponse(statusCode, sipRequest);
        response.setStatusCode(statusCode);
        if (msg != null) {
            response.setReasonPhrase(msg);
        }

        if (responseAckExtraParam != null) {
            if (responseAckExtraParam.sipURI != null && sipRequest.getMethod().equals(Request.INVITE)) {
                logger.debug("responseSdpAck SipURI: {}:{}", responseAckExtraParam.sipURI.getHost(), responseAckExtraParam.sipURI.getPort());
                AddressFactory factory = SipFactory.getInstance().createAddressFactory();
                Address concatAddress = factory.createAddress(
                        factory.createSipURI(responseAckExtraParam.sipURI.getUser(), responseAckExtraParam.sipURI.getHost() + ":" + responseAckExtraParam.sipURI.getPort()
                        ));
                response.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));
            }
            if (responseAckExtraParam.contentTypeHeader != null) {
                response.setContent(responseAckExtraParam.content, responseAckExtraParam.contentTypeHeader);
            }

            if (sipRequest.getMethod().equals(Request.SUBSCRIBE)) {
                if (responseAckExtraParam.expires == -1) {
                    logger.error("[参数不全] 2xx的SUBSCRIBE回复，必须设置Expires header");
                } else {
                    ExpiresHeader expiresHeader = SipFactory.getInstance().createHeaderFactory().createExpiresHeader(responseAckExtraParam.expires);
                    response.addHeader(expiresHeader);
                }
            }
        } else {
            if (sipRequest.getMethod().equals(Request.SUBSCRIBE)) {
                logger.error("[参数不全] 2xx的SUBSCRIBE回复，必须设置Expires header");
            }
        }
        // 发送response
        sipSender.transmitRequest(sipRequest.getLocalAddress().getHostAddress(), response);
        return response;
    }

    public Element getRootElement(RequestEvent evt) throws DocumentException {
        return getRootElement(evt, "gb2312");
    }

    public Element getRootElement(RequestEvent evt, String charset) throws DocumentException {
        if (charset == null) {
            charset = "gb2312";
        }
        Request request = evt.getRequest();
        SAXReader reader = new SAXReader();
        reader.setEncoding(charset);
        // 对海康出现的未转义字符做处理。
        String[] destStrArray = new String[]{"&lt;", "&gt;", "&amp;", "&apos;", "&quot;"};
        // 或许可扩展兼容其他字符
        char despChar = '&';
        byte destBye = (byte) despChar;
        List<Byte> result = new ArrayList<>();
        byte[] rawContent = request.getRawContent();
        if (rawContent == null) {
            return null;
        }
        for (int i = 0; i < rawContent.length; i++) {
            if (rawContent[i] == destBye) {
                boolean resul = false;
                for (String destStr : destStrArray) {
                    if (i + destStr.length() <= rawContent.length) {
                        byte[] bytes = Arrays.copyOfRange(rawContent, i, i + destStr.length());
                        resul = resul || (Arrays.equals(bytes, destStr.getBytes()));
                    }
                }
                if (resul) {
                    result.add(rawContent[i]);
                }
            } else {
                result.add(rawContent[i]);
            }
        }
        byte[] bytesResult = ByteUtils.toArray(result);

        Document xml;
        try {
            xml = reader.read(new ByteArrayInputStream(bytesResult));
        } catch (DocumentException e) {
            logger.warn("[xml解析异常]： 原文如下： \r\n{}", new String(bytesResult));
            logger.warn("[xml解析异常]： 原文如下： 尝试兼容性处理");
            String[] xmlLineArray = new String(bytesResult).split("\\r?\\n");

            // 兼容海康的address字段带有<破换xml结构导致无法解析xml的问题
            StringBuilder stringBuilder = new StringBuilder();
            for (String s : xmlLineArray) {
                if (s.startsWith("<Address")) {
                    continue;
                }
                stringBuilder.append(s);
            }
            xml = reader.read(new ByteArrayInputStream(stringBuilder.toString().getBytes()));
        }
        return xml.getRootElement();
    }

}
